/**
 @file sys_usw_nexthop_l3.c

 @date 2009-11-23

 @version v2.0

 The file contains all nexthop layer3 related callback function
*/

/****************************************************************************
 *
* Header Files
*
****************************************************************************/
#include "ctc_const.h"
#include "ctc_error.h"
#include "ctc_linklist.h"

#include "ctc_packet.h"
#include "ctc_internal_port.h"

#include "sys_usw_common.h"
#include "sys_usw_register.h"
#include "sys_usw_nexthop_api.h"
#include "sys_usw_nexthop.h"
#include "sys_usw_nexthop_hw.h"
#include "sys_usw_vlan.h"
#include "sys_usw_l3if.h"
#include "sys_usw_aps.h"
#include "drv_api.h"

extern int32 sys_usw_internal_port_allocate(uint8 lchip, ctc_internal_port_assign_para_t* p_port_assign);
extern sys_usw_nh_api_master_t* p_usw_nh_api_master[CTC_MAX_LOCAL_CHIP_NUM_PP];
extern int32 _sys_usw_nh_ipuc_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1);
int32
_sys_usw_nh_ipuc_update_dsnh_cb(uint8 lchip, sys_nh_db_arp_t* p_arp_db, uint32 nh_id)
{
    sys_nexthop_t sys_dsnh;
    sys_nh_info_com_t* p_nh_com_db = NULL;
    sys_nh_info_ipuc_t* p_nh_info = NULL;
    sys_l3if_prop_t l3if_prop;
    sys_nh_info_ext_t* p_nh_info_ext = NULL;

    CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_by_nhid(lchip, nh_id, (sys_nh_info_com_t**)&p_nh_com_db));
    p_nh_info = (sys_nh_info_ipuc_t*)(p_nh_com_db);
    p_nh_info->gport = p_arp_db->gport;

    l3if_prop.l3if_id = p_arp_db->l3if_id;
    CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info( lchip, 1,&l3if_prop));

    sys_dsnh.update_type = SYS_NH_UPDATE_TYPE_MAC_VLAN;
    sal_memcpy(sys_dsnh.mac_da, p_arp_db->mac_da, sizeof(mac_addr_t));
    sys_dsnh.dest_vlan_ptr = l3if_prop.vlan_ptr;

    sys_dsnh.offset = p_nh_com_db->hdr.dsnh_offset;

    if (CTC_FLAG_ISSET(p_nh_com_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_asic_table(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_8W, sys_dsnh.offset, &sys_dsnh));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_asic_table(lchip, SYS_NH_ENTRY_TYPE_NEXTHOP_4W, sys_dsnh.offset, &sys_dsnh));
    }

    if (CTC_FLAG_ISSET(p_nh_com_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_ipuc_add_dsfwd(lchip, p_nh_com_db, 0));
    }
    if (CTC_FLAG_ISSET(p_nh_com_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1))
    {
        CTC_ERROR_RETURN(_sys_usw_nh_ipuc_add_dsfwd(lchip, p_nh_com_db, 1));
    }
    if (CTC_FLAG_ISSET(p_nh_com_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOOP_USED))
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_loopback_l2edit(lchip, nh_id, 1));
    }

    /*update oam mep*/
    CTC_ERROR_RETURN(_sys_usw_nh_update_oam_mep(lchip, p_nh_info->pd->oam_list, p_arp_db->arp_id, NULL));

   /*for aps nexthop member to update aps group information*/
   CTC_ERROR_RETURN(sys_usw_nh_get_nhinfo_ext_by_nhid(lchip, nh_id, &p_nh_info_ext, 0));
   if (p_nh_info_ext && p_nh_info_ext->aps_list)
   {
        sys_nh_ref_list_node_t* p_ref_node = NULL;
        sys_nh_info_com_t* p_nh_com = NULL;

        p_ref_node = p_nh_info_ext->aps_list;
        while (p_ref_node)
        {
            p_nh_com = p_ref_node->p_ref_nhinfo;
            sys_usw_nh_update_aps_by_nh(lchip, p_nh_com->hdr.nh_id, p_nh_info->hdr.nh_id);
            p_ref_node = p_ref_node->p_next;
        }
   }
    return CTC_E_NONE;
}


STATIC int32
_sys_usw_nh_ipuc_update_dsnh(uint8 lchip, sys_nh_param_ipuc_t* p_nhpara,sys_nh_info_ipuc_t* p_nhdb)
{
    sys_l3if_prop_t l3if_prop;
    sys_nh_param_dsnh_t dsnh_param;
    ctc_nh_oif_info_t *p_oif;
    sys_dsl2edit_eth_t   dsl2edit;
    ctc_vlan_egress_edit_info_t  vlan_edit;
    uint32 arp_id = 0;
    ctc_ip_nh_param_t* p_ipuc_param = p_nhpara->p_ipuc_param;
    mac_addr_t mac = {0};
    uint8 l2edit_8w = 0;
    sys_nh_db_arp_t *p_arp = NULL;
    uint8 use_l2edit = CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_3W) || CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_6W);
    uint8 use_static_l2edit = 0;

    sal_memset(&dsnh_param, 0, sizeof(sys_nh_param_dsnh_t));
    sal_memset(&dsl2edit, 0, sizeof(dsl2edit));
    sal_memset(&l3if_prop, 0, sizeof(l3if_prop));

    p_oif = &p_ipuc_param->oif;
    arp_id = p_ipuc_param->arp_id;

    if (p_nhpara->hdr.l3if_id)
    {
        l3if_prop.l3if_id = p_nhpara->hdr.l3if_id;
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info(lchip, 1, &l3if_prop));
        p_nhdb->flag |= SYS_NH_IPUC_FLAG_L3IF_VALID;
        l2edit_8w = (l3if_prop.l3if_type == CTC_L3IF_TYPE_SERVICE_IF && p_oif->vid && p_oif->cvid) ? 1 : 0;
        if (p_oif->vid && p_oif->cvid && (l3if_prop.l3if_type != CTC_L3IF_TYPE_SERVICE_IF) && !arp_id)
        {
            return CTC_E_INVALID_CONFIG;
        }
    }
    else if (!(CTC_IS_CPU_PORT(p_oif->gport) || p_oif->is_l2_port || p_nhpara->hdr.is_drop))
    {
        CTC_ERROR_RETURN(sys_usw_l3if_get_l3if_info_with_port_and_vlan(lchip, p_oif->gport, p_oif->vid, p_oif->cvid, &l3if_prop));
    }

    if (((l3if_prop.l3if_type == CTC_L3IF_TYPE_PHY_IF || p_nhpara->hdr.l3if_id) && p_oif->vid)
        ||(CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)) || (p_nhpara->hdr.stats_ptr))/* if use 8w, can not use SYS_NH_OP_ROUTE_COMPACT, must use l2edit to edit L2 Header */
    {
        sal_memset(&vlan_edit, 0, sizeof(ctc_vlan_egress_edit_info_t));
        dsl2edit.output_vid = p_oif->vid;
        use_l2edit = 1;
    }

    if (CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_FPMA))
    {
        use_l2edit = 1;
        dsl2edit.fpma = 1;
        p_nhdb->flag |= SYS_NH_IPUC_FLAG_FPMA;
    }

    if(0 != sal_memcmp(p_ipuc_param->mac_sa, mac, sizeof(mac_addr_t)))/*edit mac sa, must use l2edit8w, for openflow*/
    {
        use_l2edit = 1;
        l2edit_8w  = 1;
        dsl2edit.update_mac_sa = 1;
    }

    if (CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_VXLAN_UNDERLAY))
    {
        use_l2edit = 1;
        use_static_l2edit = 1;
    }

    sal_memcpy(dsnh_param.macDa, p_ipuc_param->mac, sizeof(mac_addr_t));
    dsnh_param.dsnh_offset = p_nhdb->hdr.dsnh_offset;

    if (arp_id)
    {
        sys_nh_info_arp_param_t arp_parm;
        sal_memset(&arp_parm, 0, sizeof(sys_nh_info_arp_param_t));
        arp_parm.nh_entry_type  = SYS_NH_TYPE_IPUC;
        arp_parm.nh_id          = p_nhpara->hdr.nhid;
        arp_parm.updateNhp      = (updatenh_fn)_sys_usw_nh_ipuc_update_dsnh_cb;
        arp_parm.is_aps = p_ipuc_param->aps_en;
        arp_parm.use_l2edit = (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W) || p_nhpara->hdr.stats_ptr)? 1 : 0;
        arp_parm.use_static_l2edit = CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_VXLAN_UNDERLAY);
        CTC_ERROR_RETURN(sys_usw_nh_bind_arp_cb(SYS_PP_BASE(lchip), &arp_parm, arp_id));
        p_nhdb->pd->p_arp_nh_node = arp_parm.p_arp_nh_node;

        p_arp = (sys_usw_nh_lkup_arp_id(lchip, arp_id));
        if (NULL == p_arp)
        {
            return CTC_E_NOT_EXIST;
        }

        if ((arp_parm.use_static_l2edit) || (0 == p_arp->offset_dyn))
        {
            dsnh_param.l2edit_ptr  = p_arp->offset;
        }
        else
        {
            dsnh_param.inner_l2edit_ptr  = p_arp->offset_dyn;
        }
        /* 1) One Arp only corresponds to one ipuc nexthop in general.
        2) Multiple ipuc nexthop use the same arp, only the fisrt ipuc nexthop exists mergedsfwd mode. */
        p_nhpara->hdr.have_dsfwd |= (p_arp->pd->nh_list && p_arp->pd->nh_list->count > 1);
        sal_memcpy(dsnh_param.macDa, p_arp->mac_da, sizeof(mac_addr_t));
    }
    else if (use_l2edit)
    {
        sal_memcpy(dsl2edit.mac_da, dsnh_param.macDa, sizeof(mac_addr_t));
        if (l2edit_8w)
        {
            sal_memcpy(dsl2edit.mac_sa, p_ipuc_param->mac_sa, sizeof(mac_addr_t));
            dsl2edit.output_vid = p_oif->vid;
            dsl2edit.output_cvid = p_oif->cvid;
            if (use_static_l2edit)
            {
                CTC_ERROR_RETURN(sys_usw_nh_add_l2edit(lchip, &dsl2edit, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_8W, &dsnh_param.l2edit_ptr));
                p_nhdb->l2_edit_ptr = dsnh_param.l2edit_ptr;
                CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
            }
            else
            {
                CTC_ERROR_RETURN(sys_usw_nh_add_l2edit(lchip, &dsl2edit, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, &dsnh_param.inner_l2edit_ptr));
                p_nhdb->l2_edit_ptr = dsnh_param.inner_l2edit_ptr;
                CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_6W);
            }      
        }
        else
        {
            if (use_static_l2edit)
            {
                CTC_ERROR_RETURN(sys_usw_nh_add_l2edit(lchip, &dsl2edit, SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, &dsnh_param.l2edit_ptr));
                p_nhdb->l2_edit_ptr = dsnh_param.l2edit_ptr;
                CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
            }
            else
            {
                CTC_ERROR_RETURN(sys_usw_nh_add_l2edit(lchip, &dsl2edit, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W, &dsnh_param.inner_l2edit_ptr));
                p_nhdb->l2_edit_ptr = dsnh_param.inner_l2edit_ptr;
                CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_3W);
            }
        }
        p_nhdb->l2edit_8w = l2edit_8w;
    }

    p_nhdb->l3ifid = l3if_prop.l3if_id;
    p_nhdb->arp_id = arp_id;

    dsnh_param.dsnh_type = SYS_NH_PARAM_DSNH_TYPE_IPUC;
    dsnh_param.dest_vlan_ptr = l3if_prop.vlan_ptr;
    dsnh_param.flag  = p_nhdb->flag;
    dsnh_param.mtu_no_chk = p_nhpara->p_ipuc_param->mtu_no_chk;
    dsnh_param.cid  = p_nhpara->p_ipuc_param->cid;
    dsnh_param.logic_port  = p_nhpara->p_ipuc_param->logic_port;
    dsnh_param.stats_ptr = p_nhpara->hdr.stats_ptr;

    if(CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_TTL_NO_DEC))
    {
        CTC_SET_FLAG(dsnh_param.flag, SYS_NH_PARAM_FLAG_ROUTE_NOTTL);
    }
    if(CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_TTL_USE_PKT))
    {
        dsnh_param.use_ttl_from_pkt = 1;
    }

    if (DRV_FROM_TMM(lchip) && (dsnh_param.l2edit_ptr == 0) && (dsnh_param.inner_l2edit_ptr == 0)
        && (dsnh_param.cid > 0x3FF))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " cid exceed 0x3FF! \n");
        return CTC_E_INVALID_CONFIG;
    }
    if (CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh8w(lchip, &dsnh_param));
    }
    else
    {
        CTC_ERROR_RETURN(sys_usw_nh_write_entry_dsnh4w(lchip, &dsnh_param));
    }

    if (CTC_FLAG_ISSET(p_ipuc_param->flag, CTC_IP_NH_FLAG_VXLAN_UNDERLAY))
    {
        sys_ldp_t ldp;
        uint32 ldp_ext = 0;
        sal_memset(&ldp, 0, sizeof(ldp));
        ldp.l2edit_ptr = dsnh_param.l2edit_ptr;
        ldp.dest_vlan_ptr = dsnh_param.dest_vlan_ptr;

        if (p_nhdb->ldp_ext == 0)
        {
            if (p_ipuc_param->dsnh2_offset)
            {
                ldp_ext =  p_ipuc_param->dsnh2_offset + MCHIP_CAP(SYS_CAP_NH_LOGIC_DEST_PORT_EXT_BASE);
                p_nhdb->ldp_ext_alloc = 0;
            }
            else
            {
                CTC_ERROR_RETURN(sys_usw_nh_offset_alloc(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT_EXT, 1, &ldp_ext));
                 p_nhdb->ldp_ext_alloc = 1;
            }

            CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT, ldp_ext, &ldp));
            p_nhdb->ldp_ext = ldp_ext;
        }
    }
    else if (p_nhdb->ldp_ext)
    {
        sys_ldp_t ldp;
        sal_memset(&ldp, 0, sizeof(ldp));
        if (p_nhdb->ldp_ext_alloc)
        {
            sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT_EXT, 1, p_nhdb->ldp_ext);
        }
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT, p_nhdb->ldp_ext, &ldp));
        p_nhdb->ldp_ext =0;
        p_nhdb->ldp_ext_alloc = 0;
    }
    return CTC_E_NONE;
}
int32
_sys_usw_nh_free_ipuc_nh_resource(uint8 lchip, sys_nh_info_ipuc_t* p_nhinfo, uint32 nh_id)
{
    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW))
    {
        return CTC_E_NONE;
    }

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT))
    {
        sys_usw_nh_remove_l2edit(lchip, p_nhinfo->l2edit_8w? SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_8W : SYS_NH_ENTRY_TYPE_L2EDIT_OUTER_4W, p_nhinfo->l2_edit_ptr);
        CTC_UNSET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDIT);
    }

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_3W) || CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_6W))
    {
        if (p_nhinfo->l2edit_8w)
        {
            sys_usw_nh_remove_l2edit(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, p_nhinfo->l2_edit_ptr);
        }
        else
        {
            sys_usw_nh_remove_l2edit(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W, p_nhinfo->l2_edit_ptr);
        }

        CTC_UNSET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_3W);
        CTC_UNSET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_6W);
    }
    p_nhinfo->l2edit_8w = 0;

    if(p_nhinfo->arp_id)
    {
         sys_usw_nh_unbind_arp_cb(lchip,p_nhinfo->arp_id, 1, p_nhinfo->pd->p_arp_nh_node);
         p_nhinfo->pd->p_arp_nh_node = NULL;
    }

    p_nhinfo->arp_id = 0;
    return CTC_E_NONE;
}

int32
_sys_usw_nh_ipuc_add_dsfwd(uint8 lchip, sys_nh_info_com_t* p_com_db, uint8 is_dsfwd1)
{
   sys_nh_param_dsfwd_t dsfwd_param;
   sys_nh_info_ipuc_t* p_nhinfo = (sys_nh_info_ipuc_t*)(p_com_db);

   sal_memset(&dsfwd_param, 0, sizeof(sys_nh_param_dsfwd_t));
   dsfwd_param.nexthop_ext = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W);
   dsfwd_param.is_mcast = 0;
   dsfwd_param.drop_pkt  = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);
   dsfwd_param.dsnh_offset = p_nhinfo->hdr.dsnh_offset;
   dsfwd_param.dsfwd_offset  = p_nhinfo->hdr.dsfwd_offset;
   dsfwd_param.is_egress_edit =  CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE);
   if (p_nhinfo->arp_id)
   {
       sys_nh_db_arp_t *p_arp = NULL;
       p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_nhinfo->arp_id));
       if (NULL == p_arp)
       {
           return  CTC_E_NOT_EXIST;
       }

       if (CTC_FLAG_ISSET(p_arp->flag, SYS_NH_ARP_FLAG_REDIRECT_TO_CPU))
       {
           dsfwd_param.dest_chipid  =  SYS_MAP_CTC_GPORT_TO_GCHIP(p_arp->gport);
           dsfwd_param.is_lcpu    =   CTC_FLAG_ISSET(p_arp->flag, SYS_NH_ARP_FLAG_REDIRECT_TO_CPU);
           dsfwd_param.dsnh_offset    =   CTC_PKT_CPU_REASON_BUILD_NHPTR(CTC_PKT_CPU_REASON_ARP_MISS, 0);
       }
       else if (CTC_FLAG_ISSET(p_arp->flag, SYS_NH_ARP_FLAG_DROP))
       {
           dsfwd_param.dest_chipid  =  SYS_MAP_CTC_GPORT_TO_GCHIP(p_arp->gport);
           dsfwd_param.drop_pkt = 1;
       }
       else
       {
           dsfwd_param.dest_chipid  =  SYS_MAP_CTC_GPORT_TO_GCHIP(p_arp->gport);
           dsfwd_param.dest_id      =  CTC_MAP_GPORT_TO_LPORT(p_arp->gport);
       }
   }
   else
   {
       dsfwd_param.dest_chipid = SYS_MAP_CTC_GPORT_TO_GCHIP(p_nhinfo->gport);
       dsfwd_param.dest_id = SYS_MAP_CTC_GPORT_TO_DRV_LPORT(p_nhinfo->gport);
   }

   if (CTC_IS_CPU_PORT(p_nhinfo->gport) && (0 == p_nhinfo->arp_id))
   {
        dsfwd_param.is_cpu = 1;
        dsfwd_param.dsnh_offset    =   CTC_PKT_CPU_REASON_BUILD_NHPTR(CTC_PKT_CPU_REASON_FWD_CPU, 0);
   }

    if (CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LEN_ADJUST_EN))
    {
        sys_usw_lkup_adjust_len_index(lchip, p_nhinfo->adjust_len, &dsfwd_param.adjust_len_idx);
    }

    dsfwd_param.is_6w = dsfwd_param.truncate_profile_id || dsfwd_param.stats_ptr || dsfwd_param.is_reflective;

    dsfwd_param.logic_port_ext = is_dsfwd1? p_nhinfo->ldp_ext:0;
    CTC_ERROR_RETURN(_sys_usw_nh_add_dsfwd(lchip, p_com_db, &dsfwd_param, is_dsfwd1));

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_update_ipuc_fwd_attr(uint8 lchip, sys_nh_param_ipuc_t* p_nhpara, sys_nh_info_ipuc_t* p_nhinfo)
{
    int32 ret = 0;
    uint8 edit_dsnh = 1;
    ctc_ip_nh_param_t* p_ipuc_param = p_nhpara->p_ipuc_param;
    uint8 is_update = (p_nhpara->hdr.change_type != SYS_NH_CHANGE_TYPE_NULL);
    sys_nh_info_arp_param_t arp_parm;
    sys_nh_info_ipuc_t old_nh_info ;
    uint32 dsnh_offset = 0;
    uint32 cmd = 0;
    uint32 tbl_id = 0;
    DsNextHop8W_m data_w;
    uint32 arp_id = 0;

    CTC_MAX_VALUE_CHECK(p_ipuc_param->logic_port, MCHIP_CAP(SYS_CAP_NH_MAX_LOGIC_DEST_PORT));

    if (p_ipuc_param->aps_en)
    {
        return CTC_E_NOT_SUPPORT;
    }

    if ((0 == CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
        && (p_ipuc_param->logic_port ||  (p_ipuc_param->stats_id && g_usw_nh_master[lchip]->cid_use_4w))
        && (!CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV)))
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Should use DsNexthop8W table \n");
        return CTC_E_INVALID_CONFIG;
    }
    edit_dsnh = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_NO_HW)? 0 : 1;

    if(is_update)
    {
       sal_memcpy(&old_nh_info, p_nhinfo, sizeof(sys_nh_info_ipuc_t));
       /*reset*/
       if (p_nhinfo->arp_id)
       {
           sys_usw_nh_unbind_arp_cb(lchip, p_nhinfo->arp_id, 1, p_nhinfo->pd->p_arp_nh_node);
           arp_id = p_nhinfo->arp_id;
           old_nh_info.arp_id = 0;
        }

        sal_memset(p_nhinfo, 0, sizeof(sys_nh_info_ipuc_t));
        sys_usw_nh_copy_nh_entry_flags(lchip, &old_nh_info.hdr, &p_nhinfo->hdr);
        p_nhinfo->pd = old_nh_info.pd;
        p_nhinfo->ldp_ext = old_nh_info.ldp_ext;
        if (p_ipuc_param->stats_id)
        {
            CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip,
                                                            p_ipuc_param->stats_id,
                                                            &p_nhpara->hdr.stats_ptr));
        }

        tbl_id = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)? DsNextHop8W_t : DsNextHop4W_t;
        sal_memset(&data_w, 0, sizeof(DsNextHop8W_m));
        dsnh_offset = p_nhinfo->hdr.dsnh_offset;
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);
    }

    if (CTC_FLAG_ISSET(p_nhpara->p_ipuc_param->flag, CTC_IP_NH_FLAG_MERGE_DSFWD))
    {
       CTC_SET_FLAG(p_nhinfo->flag, SYS_NH_IPUC_FLAG_MERGE_DSFWD);
    }
    else
    {
       CTC_UNSET_FLAG(p_nhinfo->flag, SYS_NH_IPUC_FLAG_MERGE_DSFWD);
    }

    if (p_ipuc_param->adjust_length != 0)
    {
        CTC_SET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LEN_ADJUST_EN);
        p_nhinfo->adjust_len = p_ipuc_param->adjust_length ;
    }

    /*first do l3if check*/
    p_nhinfo->gport = p_ipuc_param->oif.gport;
    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "lchip = %d, edit_dsnh = %d\n", lchip, edit_dsnh);
    if (edit_dsnh)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_ipuc_update_dsnh(lchip,  p_nhpara, p_nhinfo),ret, error_proc);
    }

    if (p_nhpara->hdr.have_dsfwd)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_ipuc_add_dsfwd(lchip, (sys_nh_info_com_t*) p_nhinfo, 0),ret, error_proc);
    }

    if (DRV_FROM_AT(lchip) && p_nhpara->hdr.have_dsfwd1)
    {
        CTC_ERROR_GOTO(_sys_usw_nh_ipuc_add_dsfwd(lchip, (sys_nh_info_com_t*) p_nhinfo, 1),ret, error_proc);
    }

    if (is_update)
    {
        _sys_usw_nh_free_ipuc_nh_resource(lchip, &old_nh_info, p_nhpara->hdr.nhid);
    }

    return CTC_E_NONE;

error_proc:
      _sys_usw_nh_free_ipuc_nh_resource(lchip, p_nhinfo, p_nhpara->hdr.nhid);

     /*rollback*/
     if (is_update && edit_dsnh)
     {
         sal_memcpy(p_nhinfo, &old_nh_info,  sizeof(sys_nh_info_ipuc_t));
         p_nhinfo->arp_id = arp_id;
         /*bind arp*/
         sal_memset(&arp_parm, 0, sizeof(sys_nh_info_arp_param_t));
         arp_parm.nh_entry_type  = SYS_NH_TYPE_IPUC;
         arp_parm.nh_id          = p_nhpara->hdr.nhid;
         arp_parm.updateNhp      = (updatenh_fn)_sys_usw_nh_ipuc_update_dsnh_cb;

         if (arp_id)
         {
             CTC_ERROR_DUMP(sys_usw_nh_bind_arp_cb(lchip, &arp_parm, arp_id));
             p_nhinfo->pd->p_arp_nh_node = arp_parm.p_arp_nh_node;
         }
        tbl_id = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?DsNextHop8W_t:DsNextHop4W_t;
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, dsnh_offset, cmd, &data_w);
     }

     return ret;
}

int32
sys_usw_nh_create_ipuc_cb(uint8 lchip, sys_nh_param_com_t* p_com_nh_para,
                                sys_nh_info_com_t* p_com_db)
{
    sys_nh_param_ipuc_t* p_nh_para;
    sys_nh_info_ipuc_t* p_nhdb;
    int32 ret = 0;
    ctc_ip_nh_param_t* p_ipuc_param = NULL;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_nh_para = (sys_nh_param_ipuc_t*)(p_com_nh_para);
    p_nhdb = (sys_nh_info_ipuc_t*)(p_com_db);
    p_ipuc_param = p_nh_para->p_ipuc_param;


    if (p_ipuc_param->cid && !g_usw_nh_master[lchip]->cid_use_4w && !CTC_FLAG_ISSET(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W) )
    {
        SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Ipuc Nexthop Must using 4w mode for cid \n");
        return CTC_E_INVALID_CONFIG;
    }

    p_nhdb->hdr.nh_entry_type = SYS_NH_TYPE_IPUC;
    p_nhdb->gport = p_ipuc_param->oif.gport;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "dsnh_offset:%d  gport:0x%x vid:%d cvid:%d\n",
                   p_ipuc_param->dsnh_offset, p_ipuc_param->oif.gport, p_ipuc_param->oif.vid, p_ipuc_param->oif.cvid);

    if (p_ipuc_param->stats_id)
    {
        CTC_ERROR_RETURN(sys_usw_flow_stats_get_statsptr(lchip,
                                                           p_ipuc_param->stats_id,
                                                           &p_nh_para->hdr.stats_ptr));
    }

    if(NULL == p_nhdb->pd)
    {
        p_nhdb->pd = mem_malloc(MEM_NEXTHOP_MODULE, sizeof(sys_nh_info_ipuc_pdata_t));
        if (NULL == p_nhdb->pd)
        {
            return CTC_E_NO_MEMORY;
        }
        sal_memset(p_nhdb->pd, 0, sizeof(sys_nh_info_ipuc_pdata_t));
    }
    /*Create unresolved ipuc nh*/
    if (p_nh_para->is_unrov_nh)
    {
        sys_l3if_prop_t l3if_prop;
        CTC_SET_FLAG(p_nhdb->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);

        sal_memset(&l3if_prop, 0, sizeof(sys_l3if_prop_t));
        if (p_nh_para->hdr.l3if_id)
        {
            l3if_prop.l3if_id = p_nh_para->hdr.l3if_id;
        }
        else if (!(CTC_IS_CPU_PORT(p_ipuc_param->oif.gport) || p_ipuc_param->oif.is_l2_port || p_com_nh_para->hdr.is_drop))
        {
            CTC_ERROR_DUMP(sys_usw_l3if_get_l3if_info_with_port_and_vlan(lchip, p_ipuc_param->oif.gport, p_ipuc_param->oif.vid, p_ipuc_param->oif.cvid, &l3if_prop));
        }

        p_nhdb->l3ifid  = l3if_prop.l3if_id;

        return CTC_E_NONE;
    }

    CTC_ERROR_GOTO(_sys_usw_nh_update_ipuc_fwd_attr(lchip, p_nh_para, p_nhdb),ret, error1);
    return CTC_E_NONE;
 error1:
    if(p_nhdb->pd)
    {
        mem_free(p_nhdb->pd);
    }
    return ret;

}

/**
 @brief Callback function of delete unicast ip nexthop

 @param[in] p_com_db, pointer used to store nexthop data

 @return CTC_E_XXX
 */
int32
sys_usw_nh_delete_ipuc_cb(uint8 lchip, sys_nh_info_com_t* p_data, sys_nh_param_com_t* p_para)
{
    sys_nh_info_ipuc_t* p_nhinfo;
    sys_nh_ref_list_node_t* p_ref_node, * p_tmp_node;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    p_nhinfo = (sys_nh_info_ipuc_t*)(p_data);

    if (p_nhinfo->pd->oam_list)
    {
        sys_nh_ref_oam_node_t* p_ref_node, * p_tmp_node;
        p_ref_node = p_nhinfo->pd->oam_list;
        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }
        p_nhinfo->pd->oam_list = NULL;
    }

    if(p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
    {
        sys_usw_nh_update_ecmp_member(lchip, p_data->hdr.nh_id, SYS_NH_CHANGE_TYPE_NH_DELETE, p_para->hdr.p_nh_info_ext->ecmp_list);
        /*1. Delete ecmp  list */
        p_ref_node = p_para->hdr.p_nh_info_ext->ecmp_list;

        while (p_ref_node)
        {
            /*Remove from db*/
            p_tmp_node = p_ref_node;
            p_ref_node = p_ref_node->p_next;
            mem_free(p_tmp_node);
        }

        p_para->hdr.p_nh_info_ext->ecmp_list = NULL;
    }


    /*2. Delete this ipuc nexthop*/
    _sys_usw_nh_remove_dsfwd(lchip, p_data);
    _sys_usw_nh_free_ipuc_nh_resource(lchip, p_nhinfo, p_data->hdr.nh_id);

    if (0 != p_nhinfo->ldp_ext)
    {
        sys_ldp_t ldp;
        sal_memset(&ldp, 0, sizeof(ldp));
        if (p_nhinfo->ldp_ext_alloc)
        {
            sys_usw_nh_offset_free(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT_EXT, 1, p_nhinfo->ldp_ext);
            p_nhinfo->ldp_ext_alloc = 0;
        }
        CTC_ERROR_RETURN(sys_usw_nh_write_asic_table(lchip, SYS_NH_ENTRY_TYPE_LOGIC_DEST_PORT, p_nhinfo->ldp_ext, &ldp));
    }

    if (p_nhinfo->pd->bind_data)
    {
        mem_free(p_nhinfo->pd->bind_data);
    }
    mem_free(p_nhinfo->pd);

    return CTC_E_NONE;
}

STATIC int32
_sys_usw_nh_update_ipuc_fwd_to_unrov(uint8 lchip, sys_nh_param_ipuc_t* p_nhpara, sys_nh_info_ipuc_t* p_nhinfo)
{
    sys_nh_param_special_t nh_para_spec;
    sal_memset(&nh_para_spec, 0, sizeof(sys_nh_param_special_t));

    nh_para_spec.hdr.have_dsfwd = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD);
    nh_para_spec.hdr.have_dsfwd1 = CTC_FLAG_ISSET(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD1);
    if (nh_para_spec.hdr.have_dsfwd || nh_para_spec.hdr.have_dsfwd1)
    {
        nh_para_spec.hdr.nh_param_type = SYS_NH_TYPE_UNROV;
        nh_para_spec.hdr.is_internal_nh = TRUE;
        /*1.2 update dsfwd to unrov nh's dsfwd, write dsfwd*/
        CTC_ERROR_RETURN(sys_usw_nh_create_special_cb(lchip, (sys_nh_param_com_t*)(&nh_para_spec), (sys_nh_info_com_t*)(p_nhinfo)));

    }
    CTC_SET_FLAG(p_nhinfo->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);
    _sys_usw_nh_free_ipuc_nh_resource(lchip, p_nhinfo, p_nhpara->hdr.nhid);
    _sys_usw_nh_free_offset_by_nhinfo(lchip, SYS_NH_TYPE_IPUC, (sys_nh_info_com_t*)p_nhinfo);

    sys_usw_nh_copy_nh_entry_flags2(lchip,p_nhinfo->hdr.nh_entry_flags, &p_nhinfo->hdr);
    return CTC_E_NONE;
}



/**
 @brief Callback function used to update ipuc nexthop
 */
int32
sys_usw_nh_update_ipuc_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db,
                                sys_nh_param_com_t* p_para)
{
    sys_nh_info_ipuc_t* p_nh_info;
    sys_nh_param_ipuc_t* p_nh_para;
    sys_nh_info_dsnh_t        dsnh_info;
    int32 ret = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    CTC_EQUAL_CHECK(SYS_NH_TYPE_IPUC, p_nh_db->hdr.nh_entry_type);
    p_nh_info = (sys_nh_info_ipuc_t*)(p_nh_db);
    p_nh_para = (sys_nh_param_ipuc_t*)(p_para);

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "change_type:%d  have_dsfwd:%d \n",
                   p_nh_para->hdr.change_type, CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_DSFWD));

    if ((p_nh_para->hdr.change_type == SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR)||
        (p_nh_para->hdr.change_type == SYS_NH_CHANGE_TYPE_UNROV_TO_FWD))
    {
        if(p_nh_para->p_ipuc_param->arp_id)
        {
           CTC_ERROR_RETURN(sys_usw_nh_get_arp_oif(lchip, p_nh_para->p_ipuc_param->arp_id, &p_nh_para->p_ipuc_param->oif, (uint8*)p_nh_para->p_ipuc_param->mac, &p_para->hdr.is_drop, &p_para->hdr.l3if_id));
        }
        if(p_nh_para->p_ipuc_param->p_arp_id)
        {
           CTC_ERROR_RETURN(sys_usw_nh_get_arp_oif(lchip, p_nh_para->p_ipuc_param->p_arp_id, &p_nh_para->p_ipuc_param->p_oif, (uint8*)p_nh_para->p_ipuc_param->p_mac, &p_para->hdr.is_drop, &p_para->hdr.p_l3if_id));
        }
    }
    sal_memset(&dsnh_info, 0, sizeof(sys_nh_info_dsnh_t));
    switch (p_nh_para->hdr.change_type)
    {
    case SYS_NH_CHANGE_TYPE_FWD_TO_UNROV:

        CTC_ERROR_RETURN(_sys_usw_nh_update_ipuc_fwd_to_unrov(lchip, p_nh_para, p_nh_info));

        CTC_SET_FLAG(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);

        break;
    case SYS_NH_CHANGE_TYPE_UPDATE_FWD_ATTR:

        CTC_ERROR_RETURN(_sys_usw_nh_update_ipuc_fwd_attr(lchip, p_nh_para, p_nh_info));

        break;

    case SYS_NH_CHANGE_TYPE_UNROV_TO_FWD:

        if (!CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
        {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Current nexthop isnt unresolved nexthop \n");
            return CTC_E_INVALID_CONFIG;

        }
        p_nh_para->is_unrov_nh = FALSE;

        CTC_ERROR_RETURN(_sys_usw_nh_update_ipuc_fwd_attr(lchip, p_nh_para, p_nh_info));
        CTC_UNSET_FLAG(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV);


        break;

    case SYS_NH_CHANGE_TYPE_ADD_DYNTBL:
        {
           SYS_NH_DSFWD_CHK(p_nh_info->hdr.nh_entry_flags, p_para->hdr.is_dsfwd1);
           CTC_ERROR_RETURN(_sys_usw_nh_ipuc_add_dsfwd(lchip, p_nh_db, p_para->hdr.is_dsfwd1));
        }
        break;

    default:
        return CTC_E_INVALID_PARAM;
    }
   if (p_para->hdr.p_nh_info_ext && p_para->hdr.p_nh_info_ext->ecmp_list)
   {
       ret = (sys_usw_nh_update_ecmp_member(lchip, p_nh_para->hdr.nhid, p_nh_para->hdr.change_type, p_para->hdr.p_nh_info_ext->ecmp_list));
       if (ret)
       {
            SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " [Nexthop] Nexthop update for ecmp fail!, ret:%d \n", ret);
       }
   }
   if (p_para->hdr.p_nh_info_ext && (p_nh_para->hdr.change_type != SYS_NH_CHANGE_TYPE_ADD_DYNTBL))
   {
        sys_nh_ref_list_node_t* p_ref_node = NULL;
        sys_nh_info_com_t* p_nh_com = NULL;

        p_ref_node = p_para->hdr.p_nh_info_ext->aps_list;
        while (p_ref_node)
        {
            p_nh_com = p_ref_node->p_ref_nhinfo;
            sys_usw_nh_update_aps_by_nh(lchip, p_nh_com->hdr.nh_id, p_nh_info->hdr.nh_id);
            p_ref_node = p_ref_node->p_next;
        }
   }
  if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_LOOP_USED))
    {
        CTC_ERROR_RETURN(sys_usw_nh_update_loopback_l2edit(lchip, p_nh_para->hdr.nhid, 1));
    }
    return CTC_E_NONE;
}

/**
 @brief Callback function used to get ipuc nexthop
 */
int32
sys_usw_nh_get_ipuc_cb(uint8 lchip, sys_nh_info_com_t* p_nh_db, void* p_para)
{
    sys_nh_info_ipuc_t* p_nh_info;
    int32 ret = 0;
    ctc_ip_nh_param_t* p_ipuc_param = NULL;
    uint16 ifid = 0;
    ctc_l3if_t l3if_info;
    sys_nexthop_t dsnh;
    sys_dsl2edit_eth_t   dsl2edit;
    uint8 use_l2edit = 0;

    SYS_NH_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);

    CTC_PTR_VALID_CHECK(p_para);
    p_nh_info = (sys_nh_info_ipuc_t*)(p_nh_db);
    p_ipuc_param = (ctc_ip_nh_param_t*)p_para;

    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
    {
        CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_UNROV);
    }
    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_IPUC_FLAG_MERGE_DSFWD))
    {
       CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_MERGE_DSFWD);
    }
    if (p_nh_info->ldp_ext)
    {
       CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_VXLAN_UNDERLAY);
       p_ipuc_param->dsnh2_offset = p_nh_info->ldp_ext - MCHIP_CAP(SYS_CAP_NH_LOGIC_DEST_PORT_EXT_BASE);
    }

    if (CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_EGRESS_EDIT_MODE))
    {
        p_ipuc_param->dsnh_offset = p_nh_db->hdr.dsnh_offset;
    }
    p_ipuc_param->arp_id = p_nh_info->arp_id;
    p_ipuc_param->adjust_length = p_nh_info->adjust_len;
    p_ipuc_param->oif.gport = p_nh_info->gport;
    ifid = p_nh_info->l3ifid;
    sal_memset(&l3if_info, 0, sizeof(l3if_info));
    l3if_info.l3if_type = 0xff;
    sal_memset(&dsl2edit, 0, sizeof(dsl2edit));
    if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_3W))
    {
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_3W, p_nh_info->l2_edit_ptr, &dsl2edit));
        use_l2edit = 1;
    }
    else if (CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_HAVE_L2EDI_6W))
    {
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, SYS_NH_ENTRY_TYPE_L2EDIT_INNER_6W, p_nh_info->l2_edit_ptr, &dsl2edit));
        use_l2edit = 1;
    }

    if (!CTC_IS_CPU_PORT(p_ipuc_param->oif.gport))
    {
        ret = (sys_usw_l3if_get_l3if_id(lchip, &l3if_info, &ifid));
        if (ret != CTC_E_NOT_EXIST)
        {
            p_ipuc_param->oif.vid = l3if_info.vlan_id;
           if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_IPUC_FLAG_L3IF_VALID))
           {
               p_ipuc_param->oif.ecmp_if_id = ifid;
           }

           if (l3if_info.l3if_type == CTC_L3IF_TYPE_SERVICE_IF)
           {
                p_ipuc_param->oif.vid = dsl2edit.output_vid;
                p_ipuc_param->oif.cvid = dsl2edit.output_cvid;
           }
        }
        else
        {
            p_ipuc_param->oif.is_l2_port = 1;
        }

    }

    sal_memset(&dsnh, 0, sizeof(dsnh));
    if(!CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_IS_UNROV))
    {
        CTC_ERROR_RETURN(sys_usw_nh_read_asic_table(lchip, CTC_FLAG_ISSET(p_nh_info->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W)?
        SYS_NH_ENTRY_TYPE_NEXTHOP_8W : SYS_NH_ENTRY_TYPE_NEXTHOP_4W, p_nh_info->hdr.dsnh_offset, &dsnh));
    }

    if (dsnh.stats_ptr)
    {
        sys_usw_flow_stats_lookup_statsid(lchip, CTC_STATS_STATSID_TYPE_NEXTHOP, dsnh.stats_ptr, &p_ipuc_param->stats_id, CTC_EGRESS);
    }
    p_ipuc_param->mtu_no_chk = dsnh.mtu_check_en?0:1;
    p_ipuc_param->cid = dsnh.cid;

    if (dsnh.ttl_no_dec)
    {
       CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_TTL_NO_DEC);
    }
    if (CTC_FLAG_ISSET(p_nh_info->flag, SYS_NH_IPUC_FLAG_FPMA))
    {
       CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_FPMA);
    }

    if(p_nh_info->arp_id)
    {
        sys_nh_db_arp_t *p_arp = NULL;
        p_arp = (sys_usw_nh_lkup_arp_id(lchip, p_nh_info->arp_id));
        if (p_arp)
        {
            sal_memcpy(p_ipuc_param->mac, p_arp->mac_da, sizeof(mac_addr_t));
        }
    }
    else
    {
        sal_memcpy(p_ipuc_param->mac, dsnh.mac_da, sizeof(mac_addr_t));
    }

    if (dsnh.payload_operation == SYS_NH_OP_ROUTE_NOTTL)
    {
        CTC_SET_FLAG(p_ipuc_param->flag, CTC_IP_NH_FLAG_TTL_NO_DEC);
    }

    if (use_l2edit)
    {
        sal_memcpy(p_ipuc_param->mac_sa, dsl2edit.mac_sa, sizeof(mac_addr_t));
        sal_memcpy(p_ipuc_param->mac, dsl2edit.mac_da, sizeof(mac_addr_t));
    }

    if(CTC_FLAG_ISSET(p_nh_db->hdr.nh_entry_flags, SYS_NH_INFO_FLAG_USE_DSNH8W))
    {
        p_ipuc_param->logic_port = dsnh.logic_dest_port;
    }

    return CTC_E_NONE;
}


